package com.ikas.ai.server.module.analyse.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikas.ai.server.module.analyse.algorithm.ThreeSigmaCalculator;
import com.ikas.ai.server.module.analyse.dorisDao.DorisTrendAnalysisDAO;
import com.ikas.ai.server.module.analyse.model.dto.TrendQueryDTO;
import com.ikas.ai.server.module.analyse.model.vo.ThreeSigmaVo;
import com.ikas.ai.server.module.analyse.model.vo.TrendAnalysisExcelVo;
import com.ikas.ai.server.module.analyse.model.vo.TrendAnalysisVo;
import com.ikas.ai.server.module.instance.model.DorisWorkInstanceStepDetail;
import com.ikas.ai.utils.BeanUtils;
import com.ikas.ai.utils.DateTimeUtil;
import com.ikas.ai.utils.EasyPoiUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * 趋势分析
 *
 * @author tang.xuandong
 * @version 1.0.0
 * @date 2023/2/1 10:41
 */
@Service
public class DorisTrendAnalysisService extends ServiceImpl<DorisTrendAnalysisDAO, DorisWorkInstanceStepDetail> {

    @Autowired
    private DorisTrendAnalysisDAO dorisTrendAnalysisDAO;
    @Value("${work-instance.step-detail.cost-time.max-length:100}")
    Integer maxStepDetailCostTimeLength;

    /**
     * 分页查询
     *
     * @param req 查询条件
     * @return list
     */
    public List<TrendAnalysisVo> pageQueryTrend(TrendQueryDTO req) {
        req.setEndTime(DateTimeUtil.plusEndTime(req.getEndTime(), 1));
        final List<TrendAnalysisVo> trendAnalysis = dorisTrendAnalysisDAO.getTrendAnalysis(req);
        trendAnalysis.forEach(d -> {
            d.setStartTime(d.getStartTimestamp().toString());
            d.setEndTime(d.getEndTimestamp().toString());
        });
        return trendAnalysis;
    }

    public List<TrendAnalysisVo> listQueryTrend(TrendQueryDTO req) {
        req.setEndTime(DateTimeUtil.plusEndTime(req.getEndTime(), 1));
        final List<TrendAnalysisVo> trendAnalysis = dorisTrendAnalysisDAO.getTrendAnalysis(req);
        handleList(req, trendAnalysis);
        trendAnalysis.forEach(d -> {
            d.setStartTime(d.getStartTimestamp().toString());
            d.setEndTime(d.getEndTimestamp().toString());
        });
        return trendAnalysis;
    }

    private void handleList(TrendQueryDTO req, List<TrendAnalysisVo> trendAnalysis) {
        final ThreeSigmaVo threeSigma = getThreeSigma(req);
        if (threeSigma != null) {
            final Double upperLimit = threeSigma.getUpperLimit(); // 上限
            final Double lowerLimit = threeSigma.getLowerLimit(); // 下限
            for (TrendAnalysisVo analysis : trendAnalysis) {
                analysis.setThreeSigmaVo(ThreeSigmaVo.build(threeSigma));
                // 异常边界
                if (upperLimit != null && lowerLimit != null) {
                    if (analysis.getCostTime() > upperLimit || analysis.getCostTime() < lowerLimit) {
                        analysis.setException(true);
                    }
                }
            }
            trendAnalysis.forEach(d -> d.setAvgCostTime(threeSigma.getAvg()));
        }
        trendAnalysis.forEach(d -> {
            d.setStartTime(d.getStartTimestamp().toString());
            d.setEndTime(d.getEndTimestamp().toString());
        });
    }


    /**
     * 获取sigma信息
     *
     * @param req req
     * @return ThreeSigmaVo
     */
    public ThreeSigmaVo getThreeSigma(TrendQueryDTO req) {
        // 采样数据 && 解析
        req.setCount(maxStepDetailCostTimeLength);
        final List<Double> sampleData = dorisTrendAnalysisDAO.getSampleData(req);
        double[] sigmaValues = ThreeSigmaCalculator.calculateThreeSigma(sampleData);
        if (sigmaValues != null && sigmaValues.length != 0) {
            final ThreeSigmaVo threeSigma = new ThreeSigmaVo();
            threeSigma.setAvg(sigmaValues[0]); // 平均值，μ代表均值
            threeSigma.setStandardDeviation(sigmaValues[1]); // 标准差，σ代表标准差
            double pThreeSigma = ThreeSigmaCalculator.doubleAccuracy(sigmaValues[0] + 3 * sigmaValues[1]);
            double pTwoSigma = ThreeSigmaCalculator.doubleAccuracy(sigmaValues[0] + 2 * sigmaValues[1]);
            double pOneSigma = ThreeSigmaCalculator.doubleAccuracy(sigmaValues[0] + 1 * sigmaValues[1]);
            double nOneSigma = ThreeSigmaCalculator.doubleAccuracy(sigmaValues[0] - 1 * sigmaValues[1]);
            double nTwoSigma = ThreeSigmaCalculator.doubleAccuracy(sigmaValues[0] - 2 * sigmaValues[1]);
            double nThreeSigma = ThreeSigmaCalculator.doubleAccuracy(sigmaValues[0] - 3 * sigmaValues[1]);
            threeSigma.setPThreeSigma(pThreeSigma); // μ+3σ
            threeSigma.setPTwoSigma(pTwoSigma);     // μ+2σ
            threeSigma.setPOneSigma(pOneSigma);     // μ+1σ
            threeSigma.setNOneSigma(nOneSigma);     // μ-1σ
            threeSigma.setNTwoSigma(nTwoSigma);     // μ-2σ
            threeSigma.setNThreeSigma(nThreeSigma); // μ-3σ
            threeSigma.setUpperLimit(pThreeSigma);  // 上限
            threeSigma.setLowerLimit(nThreeSigma);  // 下限
            return threeSigma;
        }
        return null;
    }


    /**
     * 导出
     *
     * @param response response
     * @param req      dto
     */
    public void export(HttpServletResponse response, TrendQueryDTO req) {
        req.setEndTime(DateTimeUtil.plusEndTime(req.getEndTime(), 1));
        final List<TrendAnalysisVo> trendAnalysis = dorisTrendAnalysisDAO.getTrendAnalysis(req);
        handleList(req, trendAnalysis);
        final List<TrendAnalysisExcelVo> list = BeanUtils.convert(trendAnalysis, TrendAnalysisExcelVo.class);
        // Export
        EasyPoiUtil.exportExcel(list, null, "执行响应趋势分析", TrendAnalysisExcelVo.class, "TrendAnalysis.xlsx", true, response);
    }

}
